home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------
- * FILE
- * nestloop.c
- *
- * DESCRIPTION
- * routines to support nest-loop joins
- *
- * INTERFACE ROUTINES
- * ExecNestLoop - process a nestloop join of two plans
- * ExecInitNestLoop - initialize the join
- * ExecEndNestLoop - shut down the join
- *
- * NOTES
- *
- *
- * IDENTIFICATION
- * $Header: /private/postgres/src/executor/RCS/n_nestloop.c,v 1.5 1992/08/04 17:37:58 mer Exp $
- * ----------------------------------------------------------------
- */
-
- #include "executor/executor.h"
-
- RcsId("$Header: /private/postgres/src/executor/RCS/n_nestloop.c,v 1.5 1992/08/04 17:37:58 mer Exp $");
-
- /* ----------------------------------------------------------------
- * ExecNestLoop(node)
- *
- * old comments
- * Returns the tuple joined from inner and outer tuples which
- * satisfies the qualification clause.
- *
- * It scans the inner relation to join with current outer tuple.
- *
- * If none is found, next tuple form the outer relation is retrieved
- * and the inner relation is scanned from the beginning again to join
- * with the outer tuple.
- *
- * Nil is returned if all the remaining outer tuples are tried and
- * all fail to join with the inner tuples.
- *
- * Nil is also returned if there is no tuple from inner realtion.
- *
- * Conditions:
- * -- outerTuple contains current tuple from outer relation and
- * the right son(inner realtion) maintains "cursor" at the tuple
- * returned previously.
- * This is achieved by maintaining a scan position on the outer
- * relation.
- *
- * Initial States:
- * -- the outer child and the inner child
- * are prepared to return the first tuple.
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecProcNode
- ****/
- TupleTableSlot
- ExecNestLoop(node)
- NestLoop node;
- {
- NestLoopState nlstate;
- Plan innerPlan;
- Plan outerPlan;
- bool portalFlag;
- bool needNewOuterTuple;
-
- TupleTableSlot outerTupleSlot;
- TupleTableSlot innerTupleSlot;
-
- TupleDescriptor tupType;
- Pointer tupValue;
- List targetList;
- int len;
-
- List qual;
- bool qualResult;
- ExprContext econtext;
- JoinRuleInfo ruleInfo;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- ENL1_printf("getting info from node");
-
- nlstate = get_nlstate(node);
- qual = get_qpqual((Plan) node);
- outerPlan = get_outerPlan((Plan) node);
- innerPlan = get_innerPlan((Plan) node);
- ruleInfo = (JoinRuleInfo) get_ruleinfo((Join) node);
-
- /* ----------------
- * initialize expression context
- * ----------------
- */
- econtext = get_cs_ExprContext((CommonState)nlstate);
-
- /* ----------------
- * get the current outer tuple
- * ----------------
- */
- outerTupleSlot = get_cs_OuterTupleSlot((CommonState)nlstate);
- set_ecxt_outertuple(econtext, outerTupleSlot);
-
- /* ----------------
- * Ok, everything is setup for the join so now loop until
- * we return a qualifying join tuple..
- * ----------------
- */
-
- if (get_cs_TupFromTlist((CommonState)nlstate)) {
- TupleTableSlot result;
- bool isDone;
-
- result = ExecProject(get_cs_ProjInfo((CommonState)nlstate), &isDone);
- if (!isDone)
- return result;
- }
-
- ENL1_printf("entering main loop");
- for(;;) {
- /* ----------------
- * The essential idea now is to get the next inner tuple
- * and join it with the current outer tuple.
- * ----------------
- */
- needNewOuterTuple = false;
-
- /* ----------------
- * If outer tuple is not null then that means
- * we are in the middle of a scan and we should
- * restore our previously saved scan position.
- * ----------------
- */
- if (! TupIsNull((Pointer) outerTupleSlot)) {
- ENL1_printf("have outer tuple, restoring outer plan");
- ExecRestrPos(outerPlan);
- } else {
- ENL1_printf("outer tuple is nil, need new outer tuple");
- needNewOuterTuple = true;
- }
-
- /* ----------------
- * portalFlag can be thought of as a
- * "need to rescan outer relation" flag.
- * I don't really understand it beyond that.. -cim 8/31/89
- * ----------------
- */
- portalFlag = get_nl_PortalFlag(nlstate);
- if (portalFlag == false) {
- ENL1_printf("portal flag false, need new outer tuple");
- needNewOuterTuple = true;
- }
-
- /* ----------------
- * if we have an outerTuple, try to get the next inner tuple.
- * ----------------
- */
- if (!needNewOuterTuple) {
- ENL1_printf("getting new inner tuple");
-
- innerTupleSlot = ExecProcNode(innerPlan);
- set_ecxt_innertuple(econtext, innerTupleSlot);
-
- if (TupIsNull((Pointer) innerTupleSlot)) {
- ENL1_printf("no inner tuple, need new outer tuple");
- needNewOuterTuple = true;
- }
- }
-
- /* ----------------
- * loop until we have a new outer tuple and a new
- * inner tuple.
- * ----------------
- */
- while (needNewOuterTuple) {
- /* ----------------
- * If portalFlag is nil, rescan outer relation.
- * ----------------
- */
- if (portalFlag == false)
- ExecReScan(outerPlan);
-
- /* ----------------
- * now try to get the next outer tuple
- * ----------------
- */
- ENL1_printf("getting new outer tuple");
- outerTupleSlot = ExecProcNode(outerPlan);
- set_ecxt_outertuple(econtext, outerTupleSlot);
-
- /* ----------------
- * if there are no more outer tuples, then the join
- * is complete..
- * ----------------
- */
- if (TupIsNull((Pointer) outerTupleSlot)) {
- ENL1_printf("no outer tuple, ending join");
- return NULL;
- }
-
- /* ----------------
- * we have a new outer tuple so we mark our position
- * in the outer scan and save the outer tuple in the
- * NestLoop state
- * ----------------
- */
- ENL1_printf("saving new outer tuple information");
- ExecMarkPos(outerPlan);
- set_nl_PortalFlag(nlstate, true);
- set_cs_OuterTupleSlot((CommonState)nlstate, outerTupleSlot);
-
- /* ----------------
- * now rescan the inner plan and get a new inner tuple
- * ----------------
- */
-
- /* ----------------
- * Nest Loop joins with indexscans in the inner plan
- * are treated specially (hack hack hack).. since the
- * idea is to first get an outer tuple and then do
- * an index scan on the inner relation to find a matching
- * inner tuple, this means the inner indexscan's scan
- * key is now a function of the values in the outer tuple.
- * This means we have to recalculate the proper scan key
- * values so the index scan will work correctly.
- *
- * Note: the proper thing to do would be to redesign
- * things so qualifications could refer to current attribute
- * values of tuples elsewhere in the plan.. In fact, this
- * may have to be done when we start implementing
- * bushy trees.. But for now our plans are simple and
- * we can get by doing cheezy stuff.
- * ----------------
- */
- if (ExecIsIndexScan(innerPlan)) {
- ENL1_printf("recalculating inner scan keys");
- ExecUpdateIndexScanKeys((IndexScan) innerPlan, econtext);
- }
-
- ENL1_printf("rescanning inner plan");
- ExecReScan(innerPlan);
-
- /* ----------------
- * If we are running in a 'insert rule lock & stubs'
- * mode, insert the appropriate rule stubs to the
- * inner relation.
- * ----------------
- */
- if (ruleInfo != (JoinRuleInfo) NULL) {
- /*
- * NOTE: the inner plan must be a scan!
- */
- ScanState scanState;
- RelationRuleInfo relRuleInfo;
- Relation innerRelation;
- Prs2OneStub oneStub;
- HeapTuple outerHeapTuple;
- Buffer buf;
- TupleDescriptor outerTupleDesc;
- TupleDescriptor innerTupleDesc;
-
- if (!ExecIsSeqScan(innerPlan) && !ExecIsIndexScan(innerPlan)){
- elog(WARN,"Rule stub code: inner plan not a scan");
- }
-
- outerHeapTuple = (HeapTuple) ExecFetchTuple((Pointer)
- outerTupleSlot);
- buf = ExecSlotBuffer((Pointer)outerTupleSlot);
-
- /*
- * add a rule stub in the inner relation.
- */
- scanState = get_scanstate((Scan) innerPlan);
- relRuleInfo =
- get_css_ruleInfo((CommonScanState) scanState);
- innerRelation =
- get_css_currentRelation((CommonScanState)scanState);
-
- /*
- * get tuple descs for the rule manager. XXX why can't
- * the rule manager just take the econtext as an argument
- * and get this information itself? ExecGetTupType is
- * an obsolete way of doing things. -cim 6/3/91
- */
- outerTupleDesc = ExecGetTupType(outerPlan);
- innerTupleDesc = ExecGetTupType(innerPlan);
-
- oneStub =
- prs2MakeStubForInnerRelation(ruleInfo,
- outerHeapTuple,
- buf,
- outerTupleDesc,
- innerTupleDesc);
-
- prs2AddOneStub(relRuleInfo->relationStubs, oneStub);
- relRuleInfo->relationStubsHaveChanged = true;
- set_css_ruleInfo((CommonScanState)scanState, relRuleInfo);
-
- /*
- * also store this stub to the 'ruleInfo'
- */
- set_jri_stub(ruleInfo, oneStub);
-
- /*
- * update the statistics
- */
- prs2UpdateStats(ruleInfo, PRS2_ADDSTUB);
- }
-
- ENL1_printf("getting new inner tuple");
-
- innerTupleSlot = ExecProcNode(innerPlan);
- set_ecxt_innertuple(econtext, innerTupleSlot);
-
- if (TupIsNull((Pointer) innerTupleSlot)) {
- ENL1_printf("couldn't get inner tuple - need new outer tuple");
- } else {
- ENL1_printf("got inner and outer tuples");
- needNewOuterTuple = false;
- }
- }
-
- /* ----------------
- * at this point we have a new pair of inner and outer
- * tuples so we test the inner and outer tuples to see
- * if they satisify the node's qualification.
- * ----------------
- */
- ENL1_printf("testing qualification");
- qualResult = ExecQual(qual, econtext);
-
- /* ----------------
- * if we are in a 'set rule locks' mode, and the inner tuple
- * satisfies the appropriate qualification, put a new
- * lock on it.
- * ----------------
- */
- if (ruleInfo != (JoinRuleInfo) NULL) {
- RuleLock lock;
- Relation innerRelation;
- Prs2OneStub oneStub;
- HeapTuple innerHeapTuple;
- ScanState scanState;
- TupleTableSlot scanTupleSlot;
- bool newExpLocks;
- Buffer buf;
-
- if (!ExecIsSeqScan(innerPlan) && !ExecIsIndexScan(innerPlan)) {
- elog(WARN,"Rule stub code: inner plan not a scan");
- }
- scanState = get_scanstate((Scan) innerPlan);
- innerRelation = get_css_currentRelation((CommonScanState)
- scanState);
- oneStub = get_jri_stub(ruleInfo);
- scanTupleSlot = (TupleTableSlot)
- get_css_ScanTupleSlot((CommonScanState)scanState);
-
- innerHeapTuple = (HeapTuple)
- ExecFetchTuple((Pointer)scanTupleSlot);
-
- buf = ExecSlotBuffer((Pointer) scanTupleSlot);
-
- if (prs2AddLocksAndReplaceTuple(innerHeapTuple,
- buf,
- innerRelation,
- oneStub,
- &newExpLocks)) {
- prs2UpdateStats(ruleInfo, PRS2_ADDLOCK);
- }
- if (!newExpLocks)
- qualResult = false;
- }
-
- if (qualResult) {
- /* ----------------
- * qualification was satisified so we project and
- * return the slot containing the result tuple
- * using ExecProject().
- * ----------------
- */
- ProjectionInfo projInfo;
- TupleTableSlot result;
- bool isDone;
-
- ENL1_printf("qualification succeeded, projecting tuple");
-
- projInfo = get_cs_ProjInfo((CommonState)nlstate);
- result = ExecProject(projInfo, &isDone);
- set_cs_TupFromTlist((CommonState)nlstate, !isDone);
- return result;
- }
-
- /* ----------------
- * qualification failed so we have to try again..
- * ----------------
- */
- ENL1_printf("qualification failed, looping");
- }
- }
-
- /* ----------------------------------------------------------------
- * ExecInitNestLoop
- *
- * Creates the run-time state information for the nestloop node
- * produced by the planner and initailizes inner and outer relations
- * (child nodes).
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecInitNode
- ****/
- List
- ExecInitNestLoop(node, estate, parent)
- NestLoop node;
- EState estate;
- Plan parent;
- {
- NestLoopState nlstate;
- TupleDescriptor tupType;
- Pointer tupValue;
- List targetList;
- int len;
- ExprContext econtext;
- ParamListInfo paraminfo;
- int baseid;
-
- NL1_printf("ExecInitNestLoop: %s\n",
- "initializing node");
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- set_state((Plan) node, (EStatePtr)estate);
-
- /* ----------------
- * create new nest loop state
- * ----------------
- */
- nlstate = MakeNestLoopState(false);
- set_nlstate(node, nlstate);
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, (BaseNode) nlstate, parent);
- ExecAssignDebugHooks((Plan) node, (BaseNode)nlstate);
- ExecAssignExprContext(estate, (CommonState)nlstate);
-
- #define NESTLOOP_NSLOTS 1
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, (CommonState)nlstate);
-
- /* ----------------
- * now initialize children
- * ----------------
- */
- ExecInitNode(get_outerPlan((Plan)node), estate, (Plan)node);
- ExecInitNode(get_innerPlan((Plan)node), estate, (Plan) node);
- set_nl_PortalFlag(nlstate, true);
-
- /* ----------------
- * initialize tuple type and projection info
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan) node, (CommonState)nlstate);
- ExecAssignProjectionInfo((Plan) node, (CommonState) nlstate);
-
- /* ----------------
- * finally, wipe the current outer tuple clean.
- * ----------------
- */
- set_cs_OuterTupleSlot((CommonState)nlstate, NULL);
- set_cs_TupFromTlist((CommonState)nlstate, false);
-
- NL1_printf("ExecInitNestLoop: %s\n",
- "node initialized");
- return LispTrue;
- }
-
- int
- ExecCountSlotsNestLoop(node)
- Plan node;
- {
- return ExecCountSlotsNode(get_outerPlan(node)) +
- ExecCountSlotsNode(get_innerPlan(node)) +
- NESTLOOP_NSLOTS;
- }
-
- /* ----------------------------------------------------------------
- * ExecEndNestLoop
- *
- * closes down scans and frees allocated storage
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecEndNode
- ****/
- List
- ExecEndNestLoop(node)
- NestLoop node;
- {
- NestLoopState nlstate;
- Pointer tupValue;
-
- NL1_printf("ExecEndNestLoop: %s\n",
- "ending node processing");
-
- /* ----------------
- * get info from the node
- * ----------------
- */
- nlstate = get_nlstate(node);
-
- /* ----------------
- * Free the projection info
- *
- * Note: we don't ExecFreeResultType(nlstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo((CommonState)nlstate);
-
- /* ----------------
- * close down subplans
- * ----------------
- */
- ExecEndNode(get_outerPlan((Plan) node));
- ExecEndNode(get_innerPlan((Plan) node));
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple((Pointer) get_cs_ResultTupleSlot((CommonState)nlstate));
-
- NL1_printf("ExecEndNestLoop: %s\n",
- "node processing ended");
- }
-